package com.tgu.home_action.service.impl;

import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.sms.v20190711.models.SendStatus;
import com.tgu.home_action.dao.LogMapper;
import com.tgu.home_action.dao.VolunteerInformationMapper;
import com.tgu.home_action.dao.VolunteerMapper;
import com.tgu.home_action.pojo.*;
import com.tgu.home_action.pojo.exception.IMException;
import com.tgu.home_action.pojo.state.DynamicId;
import com.tgu.home_action.pojo.state.RedisHeader;
import com.tgu.home_action.pojo.state.ResponseState;
import com.tgu.home_action.service.VolunteerService;
import com.tgu.home_action.service.utils.*;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.multipart.MultipartFile;

import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Validated
@Service
public class VolunteerServiceImpl implements VolunteerService {
    @Autowired
    private MessageService messageService;
    @Autowired
    private IMService imService;
    @Autowired
    private VolunteerInformationMapper volunteerInformationMapper;
    @Autowired
    private JwtService jwtService;
    @Autowired
    private HttpService httpService;
    @Autowired
    private WXService wxService;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private VolunteerMapper volunteerMapper;
    @Autowired
    private LogMapper logMapper;
    @Autowired
    private Logger logger;
    @Autowired
    private AliYunService aliyunService;

    final String templateId = "1858351";

    @Override
    @Transactional
    public ResponseData<Volunteer> login(@NotNull(message = "code不能为空") String code) {
        Map<String, Object> data = wxService.getVolunteerOpenId(code);
        String openid = (String) data.get("openid");
        if (openid == null) {
            switch ((int) data.get("errcode")) {
                case -1:
                    logger.error("查询openid时系统繁忙，请稍后再试");
                    return new ResponseData<Volunteer>("系统繁忙，请稍候再试", -1);
                case 40029:
                    logger.error("查询openid时code无效");
                    return new ResponseData<Volunteer>("code无效", 40029);
                case 45011:
                    logger.error("请求频率过高");
                    return new ResponseData<Volunteer>("请求频率过高", 45011);
                case 40163:
                    logger.error("查询openid时code已经被使用");
                    return new ResponseData<Volunteer>("code已经被使用", 40163);
                default:
                    return new ResponseData<Volunteer>(ResponseState.ERROR.getMessage(), ResponseState.ERROR.getValue());
            }
        }
        Volunteer volunteer = volunteerMapper.getByOpenid(openid);
        if (volunteer == null) {
            volunteer = new Volunteer();
            volunteer.setOpenid(openid);
            volunteer.setState((short) 1);
            volunteerMapper.insertVolunteer(volunteer);
        }
        if (volunteer.getState() != 1) {
            return new ResponseData<>(ResponseState.ACCOUNT_IS_ILLEGAL.getMessage(), ResponseState.ACCOUNT_IS_ILLEGAL.getValue());
        }
        //储存sessionKey
        String sessionKey = (String) data.get("session_key");
        stringRedisTemplate.opsForValue().set(RedisHeader.VOLUNTEER_SESSION_KEY.getHeader() + volunteer.getId(), sessionKey);
        //储存token
        String accessToken = jwtService.getAccessToken(volunteer.getId(), "volunteer");
        String refreshToken = jwtService.getRefreshToken(volunteer.getId(), "volunteer");
        stringRedisTemplate.opsForValue().set(RedisHeader.VOLUNTEER_TOKEN.getHeader() + volunteer.getId(), accessToken);
        stringRedisTemplate.expire(RedisHeader.VOLUNTEER_TOKEN.getHeader() + volunteer.getId(), 2, TimeUnit.HOURS);
        stringRedisTemplate.opsForValue().set(RedisHeader.VOLUNTEER_REFRESH_TOKEN.getHeader() + volunteer.getId(), refreshToken);
        stringRedisTemplate.expire(RedisHeader.VOLUNTEER_REFRESH_TOKEN.getHeader() + volunteer.getId(), 15, TimeUnit.DAYS);
        return new ResponseData<Volunteer>(ResponseState.SUCCESS.getMessage(), ResponseState.SUCCESS.getValue(), accessToken, refreshToken, volunteer);

    }

    @Override
    @Transactional
    public ResponseData<Object> updateUserinfo(@NotNull(message = "encryptedData不能为空") String encryptedData, @NotNull(message = "iv不能为空") String iv, Volunteer volunteerUser) {
        Volunteer volunteer = new Volunteer();
        volunteerUser = volunteerMapper.getById(volunteerUser.getId());
        String sessionKey = stringRedisTemplate.opsForValue().get(RedisHeader.VOLUNTEER_SESSION_KEY.getHeader() + volunteerUser.getId());
        Map<String, Object> data = wxService.getUserInfo(encryptedData, sessionKey, iv);
        volunteer.setUserinfo(data);
        //判断是否储存过头像、昵称信息
        if (volunteerUser.getAvatarUrl() == null) {
            volunteer.setId(volunteerUser.getId());
            volunteerMapper.updateUserinfo(volunteer);
        }
        VolunteerInformation volunteerInformation = volunteerInformationMapper.getInformationByVolunteerId(volunteerUser.getId());
        if (volunteerInformation != null) {
            if (volunteerInformation.getSex() == null) {
                int gender = (int) data.get("gender");
                volunteerInformation.setSex((short) gender);
                volunteerInformationMapper.updateInformation(volunteerInformation);
            }
        }
        return new ResponseData<Object>(ResponseState.SUCCESS.getMessage(), ResponseState.SUCCESS.getValue());

    }

    /**
     * 更新Token
     *
     * @param refreshToken:refreshToken
     * @return token
     */
    @Override
    public ResponseData<Object> refreshToken(@NotNull(message = "refreshToken不能为空") String refreshToken) {
        Volunteer volunteer = (Volunteer) jwtService.getUser(refreshToken);
        if (volunteer == null) {
            return new ResponseData<>(ResponseState.REFRESH_TOKEN_IS_ERROR.getMessage(), ResponseState.REFRESH_TOKEN_IS_EXPIRED.getValue());
        }
        String rightToken = stringRedisTemplate.opsForValue().get(RedisHeader.VOLUNTEER_REFRESH_TOKEN.getHeader() + volunteer.getId());
        if (!refreshToken.equals(rightToken)) {
            return new ResponseData<>(ResponseState.REFRESH_TOKEN_IS_ERROR.getMessage(), ResponseState.REFRESH_TOKEN_IS_ERROR.getValue());
        }
        String newAccessToken = jwtService.getAccessToken(volunteer.getId(), "volunteer");
        String newRefreshToken = jwtService.getRefreshToken(volunteer.getId(), "volunteer");
        stringRedisTemplate.opsForValue().set(RedisHeader.VOLUNTEER_TOKEN.getHeader() + volunteer.getId(), newAccessToken);
        stringRedisTemplate.expire(RedisHeader.VOLUNTEER_TOKEN.getHeader() + volunteer.getId(), 2, TimeUnit.HOURS);
        stringRedisTemplate.opsForValue().set(RedisHeader.VOLUNTEER_REFRESH_TOKEN.getHeader() + volunteer.getId(), newRefreshToken);
        stringRedisTemplate.expire(RedisHeader.VOLUNTEER_REFRESH_TOKEN.getHeader() + volunteer.getId(), 15, TimeUnit.DAYS);
        return new ResponseData<Object>(ResponseState.SUCCESS.getMessage(), ResponseState.SUCCESS.getValue(), newAccessToken, newRefreshToken);
    }

    /**
     * 绑定手机号时获取验证码
     */
    @Override
    public ResponseData<Object> getBindCode(String phone, Volunteer volunteerUser) {
        String code = StringService.getCode();
        try {
            SendStatus sendStatus = messageService.sendMessage(phone, templateId, new String[]{code});
            if (!sendStatus.getCode().equals("Ok")) {
                return new ResponseData<>("短信发送失败", 500);
            }
        } catch (TencentCloudSDKException e) {
            e.printStackTrace();
            return new ResponseData<>("短信发送失败", 500);
        }
        stringRedisTemplate.opsForValue().set(RedisHeader.VOLUNTEER_BIND_CODE.getHeader() + phone + volunteerUser.getId(), code);
        stringRedisTemplate.expire(RedisHeader.VOLUNTEER_BIND_CODE.getHeader() + phone + volunteerUser.getId(), 5, TimeUnit.MINUTES);
        return new ResponseData<>(ResponseState.SUCCESS.getMessage(), ResponseState.SUCCESS.getValue());
    }

    /**
     * 修改手机号时获取验证码
     */
    @Override
    public ResponseData<Object> getUpdateCode(String phone, Volunteer volunteerUser) {
        String code = StringService.getCode();
        try {
            SendStatus sendStatus = messageService.sendMessage(phone, templateId, new String[]{code});
            if (!sendStatus.getCode().equals("Ok")) {
                return new ResponseData<>("短信发送失败", 500);
            }
        } catch (TencentCloudSDKException e) {
            e.printStackTrace();
            return new ResponseData<>("短信发送失败", 500);
        }
        stringRedisTemplate.opsForValue().set(RedisHeader.VOLUNTEER_UPDATE_CODE.getHeader() + phone + volunteerUser.getId(), code);
        stringRedisTemplate.expire(RedisHeader.VOLUNTEER_UPDATE_CODE.getHeader() + phone + volunteerUser.getId(), 5, TimeUnit.MINUTES);
        return new ResponseData<>(ResponseState.SUCCESS.getMessage(), ResponseState.SUCCESS.getValue());

    }

    /**
     * 绑定/更改手机号
     */
    @Override
    public ResponseData<Object> bindPhone(@NotNull(message = "phone不能为空") @Pattern(regexp = "^[1]([3-9])[0-9]{9}$", message = "手机号格式错误") String phone, @NotNull(message = "code不能为空") String code, Volunteer volunteerUser) {
        Volunteer volunteer = volunteerMapper.getById(volunteerUser.getId());
        String rightCode = null;
        if (volunteer.getPhone() == null) {
            rightCode = stringRedisTemplate.opsForValue().get(RedisHeader.VOLUNTEER_BIND_CODE.getHeader() + phone + volunteerUser.getId());
        } else {
            rightCode = stringRedisTemplate.opsForValue().get(RedisHeader.VOLUNTEER_UPDATE_CODE.getHeader() + phone + volunteerUser.getId());
        }
        if (rightCode == null) {
            return new ResponseData<>(ResponseState.CODE_NOT_EXIST.getMessage(), ResponseState.CODE_NOT_EXIST.getValue());
        }
        if (!rightCode.equals(code)) {
            return new ResponseData<>(ResponseState.CODE_IS_ERROR.getMessage(), ResponseState.CODE_IS_ERROR.getValue());
        }
        volunteerUser.setPhone(phone);
        volunteerMapper.updatePhone(volunteerUser);
        if (volunteer.getPhone() == null) {
            stringRedisTemplate.delete(RedisHeader.VOLUNTEER_BIND_CODE.getHeader() + phone + volunteerUser.getId());

        } else {
            stringRedisTemplate.delete(RedisHeader.VOLUNTEER_UPDATE_CODE.getHeader() + phone + volunteerUser.getId());
        }
        return new ResponseData<>(ResponseState.SUCCESS.getMessage(), ResponseState.SUCCESS.getValue());
    }

    /**
     * 上传图片
     */
    @Override
    public ResponseData<String> uploadPhoto(MultipartFile photo, Volunteer volunteerUser) throws IOException {
        InputStream inputStream = photo.getInputStream();
        if (!FileService.isImage(inputStream)) {
            return new ResponseData<>(ResponseState.FILE_FORMAT_ERROR.getMessage(), ResponseState.FILE_FORMAT_ERROR.getValue());
        }
        photo.getOriginalFilename();
        String url = aliyunService.uploadFile(photo.getInputStream(), "volunteer/" + volunteerUser.getId() + "/" + StringService.getRandomString() + FileService.getFileSuffix(photo.getOriginalFilename()));
        return new ResponseData<>(ResponseState.SUCCESS.getMessage(), ResponseState.SUCCESS.getValue(), url);
    }

    /**
     * 更换头像
     */
    @Override
    public ResponseData<String> updateAvatar(@NotNull(message = "avatarUrl不能为空") String avatarUrl, Volunteer volunteerUser) {
        volunteerUser.setAvatarUrl(avatarUrl);
        volunteerMapper.updateUserinfo(volunteerUser);
        return new ResponseData<String>(ResponseState.SUCCESS.getMessage(), ResponseState.SUCCESS.getValue());
    }

    /**
     * 获取志愿者数量
     */
    @Override
    public ResponseData<Integer> getVolunteerNumber(VolunteerInformation volunteerInformation) {
        int number = volunteerInformationMapper.getVolunteerNumber(volunteerInformation);
        return new ResponseData<>(ResponseState.SUCCESS.getMessage(), ResponseState.SUCCESS.getValue(), number);
    }

    /**
     * 查询注册的志愿者数量
     */
    @Override
    public ResponseData<Integer> getRegisterVolunteerNumber(Admin admin) {
        int number = volunteerInformationMapper.getRegisterNum(admin);
        return new ResponseData<>(ResponseState.SUCCESS.getMessage(), ResponseState.SUCCESS.getValue(), number);

    }

    /**
     * 获取在线的志愿者数量
     */
    @Override
    public ResponseData<Integer> getOnlineVolunteerNumber(VolunteerInformation volunteerInformation) {
        Set<String> volunteers = stringRedisTemplate.opsForSet().members(RedisHeader.VOLUNTEER_ONLINE.getHeader());
        int number = 0;
        List<Integer> volunteerIds = new ArrayList<>();
        if (volunteers != null) {
            for (String volunteerId : volunteers) {
                volunteerIds.add(Integer.valueOf(volunteerId));
            }
            number = volunteerInformationMapper.getOnlineVolunteerNumber(volunteerInformation, volunteerIds);

        }
        return new ResponseData<>(ResponseState.SUCCESS.getMessage(), ResponseState.SUCCESS.getValue(), number);
    }

    /**
     * 获取IM的UserSig
     */
    @Override
    public ResponseData<String> getUserSig(Volunteer volunteer) throws IMException {
        Boolean isExist = imService.accountCheck("volunteer_" + volunteer.getId());
        if (!isExist) {
            imService.insertUser("volunteer_" + volunteer.getId(), volunteerInformationMapper.getNameByVolunteerId(volunteer.getId()), null);
            imService.setMessage("volunteer_" + volunteer.getId(), "volunteer", volunteer.getId());
        }
        return new ResponseData<>(ResponseState.SUCCESS.getMessage(), ResponseState.SUCCESS.getValue(), imService.getUserSig("volunteer_" + volunteer.getId()));
    }

    /**
     * 加入群组
     */
    @Override
    public ResponseData<Object> joinGroup(Integer caseId, Volunteer volunteer) {
          String groupId = stringRedisTemplate.opsForValue().get(RedisHeader.GROUP_ID.getHeader() + caseId);
        if (groupId == null) {
            logger.error("该案件不存在群组");
            return  new ResponseData<>(ResponseState.GROUP_NOT_EXIST.getMessage(), ResponseState.GROUP_NOT_EXIST.getValue());
        }
        Boolean isExist = null;
        try {
            isExist = imService.accountCheck("volunteer_" + volunteer.getId());
            String name = volunteerInformationMapper.getNameByVolunteerId(volunteer.getId());
            if (!isExist) {
                imService.insertUser("volunteer_" + volunteer.getId(), name, null);
                imService.setMessage("volunteer_" + volunteer.getId(), "volunteer", volunteer.getId());
            }
            imService.addMember(groupId, "volunteer_" + volunteer.getId());
            //发送系统通知
            imService.sendGroupMsg(groupId, "志愿者" + name + "加入案件");
            return new ResponseData<>(ResponseState.SUCCESS.getMessage(), ResponseState.SUCCESS.getValue());
        } catch (IMException e) {
            e.printStackTrace();
            return new ResponseData<>(ResponseState.ERROR.getMessage(),ResponseState.ERROR.getValue());
        }
    }

}
